package br.com.spam.pipeline.core;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

import br.com.spam.pipeline.ConverterHelper;
import br.com.spam.pipeline.SegFaultException;

public class Memory
{
	public static final int SIZE = 4000;

	private int[] recentUsed = new int[4];
	private int[] memory = new int[SIZE];

	public Memory()
	{
		for (int i = 0; i < 4; i++)
			this.recentUsed[i] = 0;

		try
		{
			this.parseBinaryStringMemory("resources/memory.txt");
		}
		catch (IOException e)
		{
			throw new RuntimeException(e);
		}
	}

	private void parseBinaryStringMemory(String path) throws IOException
	{
		BufferedReader bf = new BufferedReader(new FileReader(path));
		for (int i = 0; i < SIZE * 32; i += 32)
		{
			char[] buffer = new char[32];
			bf.read(buffer, 0, 32);
			this.memory[i / 32] = ConverterHelper.charToInt(buffer);
		}
	}

	public int load(int address)
	{
		try
		{
			int ans = this.memory[address / 4];
			this.recentUsedUpdate(address);
			return ans;
		}
		catch (ArrayIndexOutOfBoundsException ex)
		{
			throw new SegFaultException(address);
		}
	}

	public MemoryPosition[] getRecentUsed()
	{
		MemoryPosition[] recentUsed = new MemoryPosition[4];
		for (int i = 0; i < 4; i++)
			recentUsed[i] = new MemoryPosition(this.recentUsed[i],
					this.memory[this.recentUsed[i] / 4]);
		return recentUsed;
	}

	public void store(int address, int value)
	{
		try
		{
			this.memory[address / 4] = value;
			this.recentUsedUpdate(address);
		}
		catch (ArrayIndexOutOfBoundsException ex)
		{
			throw new SegFaultException(address);
		}
	}

	private void recentUsedUpdate(int address)
	{
		for (int i = 0; i < 3; i++)
			this.recentUsed[i] = this.recentUsed[i + 1];
		this.recentUsed[3] = address;
	}
}
